package com.yuantu.judiciary.serviceimpl;

import com.yuantu.judiciary.dao.*;
import com.yuantu.judiciary.exception.enums.MembershipRankExceptionEnum;
import com.yuantu.judiciary.model.domain.*;
import com.yuantu.judiciary.model.enums.EndpointType;
import com.yuantu.judiciary.model.enums.InviteCodeType;
import com.yuantu.judiciary.model.vo.*;
import com.yuantu.judiciary.service.IMembershipRankService;
import com.yuantu.judiciary.utils.AssertUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 邀请码
 *
 * @author syw
 * @since 2023-08-18
 **/
@Service
@RequiredArgsConstructor
public class MembershipRankServiceImpl implements IMembershipRankService {


    private final IMembershipRankDao membershipRankDao;

    private final IAccountDao accountDao;

    private final IDiscountCodeDao discountCodeDao;

    private final IExtractPointDao extractPointDao;

    private final IInviteCodeDao inviteCodeDao;

    private final IInviteRecordDao inviteRecordDao;

    @Override
    public List<MembershipRankVO> membershipRankList() {

        List<MembershipRankDO> content = membershipRankDao.findMembershipRankList();
        List<MembershipRankVO> result = new ArrayList<>();
        for (MembershipRankDO membershipRank : content) {
            MembershipRankVO membershipRankInfo = new MembershipRankVO();
            membershipRankInfo.setMembershipRankId(membershipRank.getId());
            membershipRankInfo.setRank(membershipRank.getMembershipRank());
            BeanUtils.copyProperties(membershipRank, membershipRankInfo);
            result.add(membershipRankInfo);
        }
        return result;
    }

    @Override
    public Long updateMembershipRank(MembershipRankVO membershipRank) {

        List<MembershipRankDO> membershipRankDaoInfos = membershipRankDao.findInfos();
        if (membershipRank.getMembershipRankId() == null) {
            if (!CollectionUtils.isEmpty(membershipRankDaoInfos)) {
                membershipRankDaoInfos = membershipRankDaoInfos.stream().filter(s -> (membershipRank.getLowScore() >= s.getLowScore()
                        && membershipRank.getLowScore() <= s.getUpScore())
                        || (membershipRank.getUpScore() >= s.getLowScore() && membershipRank.getUpScore() <= s.getUpScore())).collect(Collectors.toList());
                AssertUtil.assertTrue(CollectionUtils.isEmpty(membershipRankDaoInfos), MembershipRankExceptionEnum.MEMBERSHIP_RANK_RANGE_ERROR);
            }
            MembershipRankDO membershipRankDO = new MembershipRankDO();
            membershipRankDO.setMembershipRank(membershipRank.getRank());
            membershipRankDO.setScore(membershipRank.getScore());
            membershipRankDO.setLowScore(membershipRank.getLowScore());
            membershipRankDO.setUpScore(membershipRank.getUpScore());
            membershipRankDao.save(membershipRankDO);
            membershipRank.setMembershipRankId(membershipRankDO.getId());
        } else {
            membershipRankDaoInfos = membershipRankDaoInfos.stream().filter(s -> !s.getId().equals(membershipRank.
                    getMembershipRankId())).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(membershipRankDaoInfos)) {
                membershipRankDaoInfos = membershipRankDaoInfos.stream().filter(s -> (membershipRank.getLowScore() >= s.getLowScore()
                        && membershipRank.getLowScore() <= s.getUpScore())
                        || (membershipRank.getUpScore() >= s.getLowScore() && membershipRank.getUpScore() <= s.getUpScore())).collect(Collectors.toList());
                AssertUtil.assertTrue(CollectionUtils.isEmpty(membershipRankDaoInfos), MembershipRankExceptionEnum.MEMBERSHIP_RANK_RANGE_ERROR);
            }
            MembershipRankDO existMembershipRank = membershipRankDao.findInfoById(membershipRank.getMembershipRankId());
            existMembershipRank.setMembershipRank(membershipRank.getRank());
            existMembershipRank.setScore(membershipRank.getScore());
            existMembershipRank.setLowScore(membershipRank.getLowScore());
            existMembershipRank.setUpScore(membershipRank.getUpScore());
            membershipRankDao.save(existMembershipRank);
        }
        return membershipRank.getMembershipRankId();
    }

    @Override
    public List<MembershipNumVO> getMembershipNum() {
        Map<Long, String> membershipRankMap = membershipRankDao.findInfos().stream().collect(Collectors.toMap(MembershipRankDO::getId, MembershipRankDO::getMembershipRank));
        Map<Long, List<AccountDO>> accountMap = accountDao.findAllInfos().stream().filter(s -> s.getOrigin() != EndpointType.PLATFORM).
                collect(Collectors.groupingBy(AccountDO::getMembershipRankId));
        List<MembershipNumVO> result = new ArrayList<>();
        for (Long membershipRankId : accountMap.keySet()) {
            MembershipNumVO membershipNum = new MembershipNumVO();
            membershipNum.setRank(membershipRankMap.get(membershipRankId));
            membershipNum.setNum(accountMap.get(membershipRankId).size());
            result.add(membershipNum);
        }
        return result;
    }

    @Override
    public PageVO<MembershipInfoVO> membershipManageList(String accountInfo, Pageable pageable) {

        Page<IAccountDao.SimpleAccountInfo> pageInfos = accountDao.findInfoByUserNameOrPhone(accountInfo, pageable);
        List<IAccountDao.SimpleAccountInfo> content = pageInfos.getContent();
        if (CollectionUtils.isEmpty(content)) {
            return new PageVO<>(pageInfos.getTotalElements(), new ArrayList<>());
        }
        List<Long> accountIds = content.stream().map(IAccountDao.SimpleAccountInfo::getAccountId).collect(Collectors.toList());
        Map<Long, InviteCodeDO> inviteCodeMap = inviteCodeDao.findInfosByOperatorIdInAndTypeAndDeletedFalse(accountIds,
                InviteCodeType.INVITE).stream().sorted(Comparator.comparing(InviteCodeDO::getCreateTime)).collect(Collectors.
                toMap(InviteCodeDO::getOperatorId, Function.identity(), (s1, s2) -> s2));
        List<String> accountInfos = new ArrayList<>();
        for (Long accountId : accountIds) {
            accountInfos.add(accountId.toString());
        }
        List<DiscountCodeDO> discountCodeInfos = discountCodeDao.findInfosByAccountInfoInAndIsValidAndDeletedFalse(accountInfos, true);
        Map<String, DiscountCodeDO> discountCodeMap = discountCodeInfos.stream().collect(Collectors.toMap(DiscountCodeDO::getAccountInfo,
                Function.identity(), (s1, s2) -> s2));
        Map<Long, List<ExtractPointDO>> extractPointMap = extractPointDao.findInfosByCreatorIdInAndDeletedFalse(accountIds).stream().
                collect(Collectors.groupingBy(ExtractPointDO::getCreatorId));
        Map<Long, MembershipRankDO> membershipRankMap = membershipRankDao.findInfos().stream().collect(Collectors.toMap(MembershipRankDO::getId, Function.identity()));
        List<MembershipInfoVO> result = new ArrayList<>();
        for (IAccountDao.SimpleAccountInfo accountSimple : content) {
            MembershipInfoVO membershipInfo = new MembershipInfoVO();
            membershipInfo.setAccountId(accountSimple.getAccountId());
            membershipInfo.setAccountInfo(accountSimple.getPhone());
            membershipInfo.setOwner(accountSimple.getUsername());
            MembershipRankDO membershipRank = membershipRankMap.getOrDefault(accountSimple.getMembershipRankId(), new MembershipRankDO());
            membershipInfo.setMembershipRankId(membershipRank.getId());
            membershipInfo.setRank(membershipRank.getMembershipRank());
            InviteCodeDO inviteCode = inviteCodeMap.getOrDefault(accountSimple.getAccountId(), new InviteCodeDO());
            membershipInfo.setDistributeId(inviteCode.getId());
            membershipInfo.setDistributeCode(inviteCode.getInviteCode());
            DiscountCodeDO discountCode = discountCodeMap.getOrDefault(accountSimple.getAccountId().toString(), new DiscountCodeDO());
            membershipInfo.setRecommendCodeId(discountCode.getId());
            membershipInfo.setRecommendCode(discountCode.getDiscountCode());
            membershipInfo.setHistoryScore(accountSimple.getHistoryScore() == null ? 0.0 : accountSimple.getHistoryScore());
            Double extractPoint = extractPointMap.getOrDefault(accountSimple.getAccountId(), new ArrayList<>()).stream().mapToDouble(ExtractPointDO::getPoint).sum();
            membershipInfo.setPoint(accountSimple.getHistoryScore() == null ? 0.0 : accountSimple.getHistoryScore() - extractPoint);
            result.add(membershipInfo);
        }
        return new PageVO<>(pageInfos.getTotalElements(), result);
    }

    @Transactional
    @Override
    public Boolean updateMembershipInfo(MembershipSimpleInfoVO membershipSimple) {

        if ((membershipSimple.getDistributeCode() != null && membershipSimple.getDistributeId() == null) ||
                (membershipSimple.getDistributeCode() == null && membershipSimple.getDistributeId() != null)
                || (membershipSimple.getRecommendCodeId() != null && membershipSimple.getRecommendCode() == null)
                || (membershipSimple.getRecommendCodeId() == null && membershipSimple.getRecommendCode() != null)) {
            return false;
        }
        InviteCodeDO existInviteCode = inviteCodeDao.findByIdAndDeletedFalse(membershipSimple.getDistributeId());
        if (existInviteCode != null) {
            inviteRecordDao.updateInviteCode(existInviteCode.getInviteCode(), membershipSimple.getDistributeCode());
            existInviteCode.setInviteCode(membershipSimple.getDistributeCode());
            inviteCodeDao.save(existInviteCode);
        }
        DiscountCodeDO discountCode = discountCodeDao.findDiscountCodeByIdAndDeletedFalse(membershipSimple.getRecommendCodeId());
        if (discountCode != null) {
            discountCode.setDiscountCode(membershipSimple.getRecommendCode());
            discountCodeDao.save(discountCode);
        }
        AccountDO account = accountDao.findByIdAndDeletedFalse(membershipSimple.getAccountId());
        if (account != null) {
            account.setMembershipRankId(membershipSimple.getMembershipRankId());
            accountDao.save(account);
        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean removeMembershipRank(Long membershipRankId) {

        membershipRankDao.removeInfo(membershipRankId);
        return true;
    }
}
